using JetBrains.Annotations;
using JSG.BubbleShoot.ScriptableObjects;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using WeChatWASM;

namespace JSG.BubbleShoot
{
    public class GameControl : MonoBehaviour
    {

        [SerializeField]
        private GameObject m_CandyPrefab;
        [SerializeField]
        private GameObject m_BombPrefab;
        [SerializeField]
        private GameObject m_RockPrefab;

        [HideInInspector]
        public int m_CurrentPlayerPower;
        [HideInInspector]
        public Player m_CurrentPlayerBall;

        [SerializeField]
        private GameObject[] m_PlayerBallPrefabs;



        [HideInInspector]
        public bool m_GameOver;
        [HideInInspector]
        public bool m_GameWon;

        [HideInInspector]
        public bool m_Explosion;

        [SerializeField]
        private GameObject m_PopParticle;

        [SerializeField]
        private GameObject m_RespawnParticle;

        [SerializeField]
        private GameObject m_LightningParticle;

        [SerializeField]
        private GameObject m_FireworkParticle;

        [HideInInspector]
        public int[] m_ColorCount;

        public static GameControl m_Current;

        [HideInInspector]
        public List<Candy> m_Candies;
        [HideInInspector]
        public List<GameObject> m_CandyRings;

        [HideInInspector]
        public int m_CandyCounter;

        [HideInInspector]
        public int m_LimitCounter;

        public int m_BallCount = 10;

        [SerializeField]
        private GameObject m_AimRotation;

        [HideInInspector]
        public int m_State = 0;

        [HideInInspector]
        public bool m_WaitForNext = false;
        [HideInInspector]
        public float m_WaitTime = 0;
        [HideInInspector]
        public bool m_BallDestroyed = false;
        [HideInInspector]
        public int m_CurrentColor = 0;
        [HideInInspector]
        public int m_NextColor = 0;

        [SerializeField, Space]
        private Content m_Contents;
        [SerializeField, Space]
        private DataStorage m_DataStorage;

        private void Awake()
        {
            m_Current = this;
        }
        // Start is called before the first frame update
        void Start()
        {
            m_State = 0;
            m_CurrentPlayerPower = 0;
            m_LimitCounter = -1;

            m_BallCount = 10;

            m_ColorCount = new int[6];
            m_Candies = new List<Candy>();
            m_CandyRings = new List<GameObject>();


            m_CurrentColor = 0;
            m_NextColor = -1;

            //设置帧率为60
            Application.targetFrameRate = 60;
            StartCoroutine(Co_StartLevel());
        }

        // Update is called once per frame
        void Update()
        {


            if (m_State == 1)
            {
                if (m_BallCount <= 0)
                {
                    if (m_CandyCounter != m_Candies.Count)
                    {
                        m_State = 3; // lose
                        CameraControl.Current.StartShake(1, 10);
                        UISystem.ShowUI("LoseUI");
                        UISystem.RemoveUI("GameUI");
                        WX.NotifyMiniProgramPlayableStatus(new NotifyMiniProgramPlayableStatusOption() {isEnd = true});
                        Invoke("ReloadScene", 4);
                    }
                }
                else if (m_CandyCounter == m_Candies.Count)
                {
                    m_State = 4; // win
                    UISystem.ShowUI("WinUI");
                    UISystem.RemoveUI("GameUI");
                    WX.NotifyMiniProgramPlayableStatus(new NotifyMiniProgramPlayableStatusOption() {isEnd = true});
                    StartCoroutine(Co_HandleWin());
                }

            }
            else if (m_State == 2)
            {
                if (m_BallDestroyed && m_WaitTime > 1)
                {
                    m_BallDestroyed = false;
                    m_WaitTime = 0;

                    if (m_BallCount <= 0 && m_CandyCounter < m_Candies.Count)
                    {
                        m_State = 3; // lose
                        CameraControl.Current.StartShake(1, 10);
                        UISystem.ShowUI("LoseUI");
                        UISystem.RemoveUI("GameUI");
                        Invoke("ReloadScene", 4);
                    }
                    else
                    {
                        SpawnPlayer();
                    }
                }
            }

            m_WaitTime += Time.deltaTime;


            if (m_LimitCounter == 1)
            {
                //StartUpdateRadius();
                //for (int i = 0; i < 5; i++)
                //{
                //    m_CandyRings[i].GetComponent<Ring>().UpdateRadius(5);
                //}
                m_LimitCounter = 0;
            }


            //for (int i = 0; i < m_CandyRings.Count; i++)
            //{
            //    if (m_CandyRings[i].GetComponent<Ring>().m_Radius <= 10)
            //    {
            //        if (!m_GameOver)
            //        {
            //            UISystem.ShowUI("LoseUI");
            //            UISystem.RemoveUI("GameUI");
            //            m_GameOver = true;
            //        }
            //    }
            //}

            m_AimRotation.transform.Rotate(0, 0, 100 * Time.deltaTime);


        }

        public void ShootBall()
        {
            if (m_CurrentPlayerBall != null)
            {
                m_State = 2;
                m_CurrentPlayerBall.m_Body.velocity = 150 * m_AimRotation.transform.right;
                m_CurrentPlayerBall.m_Shot = true;
                m_AimRotation.gameObject.SetActive(false);

                if (m_CurrentPlayerPower > 0)
                {
                    m_DataStorage.m_PowerCounts[m_CurrentPlayerPower - 1]--;
                }

                m_CurrentPlayerPower = 0;
                m_BallCount--;
            }
        }

        public void SpawnPlayer()
        {
            if (m_State == 0 || m_State == 2)
            {
                m_State = 1;
                CreatePlayerBall();
            }
        }

        public void CreatePlayerBall()
        {
            GameObject obj1 = Instantiate(m_RespawnParticle);
            obj1.transform.position = new Vector3(0, 0, -2);
            Destroy(obj1, 3);

            m_AimRotation.SetActive(true);

            if (m_CurrentPlayerBall != null)
            {
                Destroy(m_CurrentPlayerBall.gameObject);
                m_CurrentPlayerBall = null;
            }

            GameObject obj = Instantiate(m_PlayerBallPrefabs[m_CurrentPlayerPower], new Vector3(0, 0, 0), Quaternion.identity);
            m_CurrentPlayerBall = obj.GetComponent<Player>();

            if (m_CurrentPlayerPower == 0)
            {
                if (m_NextColor == -1)
                {
                    for (int i = 0; i < 20; i++)
                    {
                        int randomNum = UnityEngine.Random.Range(0, 6);
                        if (m_ColorCount[randomNum] != 0)
                        {
                            m_CurrentColor = randomNum;
                            m_CurrentPlayerBall.SetColor(m_CurrentColor);

                            break;
                        }
                    }

                    for (int i = 0; i < 20; i++)
                    {
                        int randomNum = UnityEngine.Random.Range(0, 6);
                        if (m_ColorCount[randomNum] != 0 && randomNum != m_CurrentColor)
                        {
                            m_NextColor = randomNum;
                            break;
                        }
                    }
                }
                else
                {
                    m_CurrentColor = m_NextColor;
                    m_CurrentPlayerBall.SetColor(m_NextColor);
                    for (int i = 0; i < 20; i++)
                    {
                        int randomNum = UnityEngine.Random.Range(0, 6);
                        if (m_ColorCount[randomNum] != 0 && randomNum != m_CurrentColor)
                        {
                            m_NextColor = randomNum;
                            break;
                        }
                    }
                }
            }
        }

        public void SwitchColor()
        {
            int num = m_CurrentColor;
            m_CurrentColor = m_NextColor;
            m_NextColor = num;

            if (m_CurrentPlayerBall != null)
            {
                m_CurrentPlayerBall.SetColor(m_CurrentColor);
            }

            GameObject obj1 = Instantiate(m_RespawnParticle);
            obj1.transform.position = new Vector3(0, 0, -2);
            Destroy(obj1, 3);
        }

        public void SelectPower(int num)
        {
            if (m_State == 1)
            {
                if (m_DataStorage.m_PowerCounts[num] > 0)
                {
                    if (num == 2)
                    {
                        LightningPower();
                        m_DataStorage.m_PowerCounts[2]--;
                    }
                    else
                    {
                        m_CurrentPlayerPower = num + 1;

                        CreatePlayerBall();
                    }
                }
                else
                {

                }
            }
        }

        public void HandleInputShoot()
        {
            if (m_State == 1 && m_BallCount > 0 && m_CandyCounter < m_Candies.Count)
            {
                ShootBall();
            }
        }
        public void SpawnFromEditor()
        {
            GameObject levelObj = m_Contents.m_Levels[m_DataStorage.Level].m_LevelPrefab;
            EditorBallBase[] balls = levelObj.GetComponentsInChildren<EditorBallBase>();

            for (int i = 0; i < balls.Length; i++)
            {
                if (balls[i].m_TypeNum == 0)
                {
                    GameObject obj = Instantiate(m_CandyPrefab);
                    Candy candy = obj.GetComponent<Candy>();
                    candy.transform.localPosition = balls[i].transform.localPosition;
                    candy.SetColor(balls[i].m_ColorNum);
                    m_Candies.Add(candy);
                    m_ColorCount[candy.m_ColorNum]++;
                }
                else if (balls[i].m_TypeNum == 1)
                {
                    GameObject obj = Instantiate(m_BombPrefab);
                    obj.transform.localPosition = balls[i].transform.localPosition;
                }
                else if (balls[i].m_TypeNum == 2)
                {
                    GameObject obj = Instantiate(m_RockPrefab);
                    obj.transform.localPosition = balls[i].transform.localPosition;
                }
            }
            //m_CandyRings = new List<GameObject>();
            //for (int i = 0;i<m_LevelBase.m_Rings.Length;i++)
            //{
            //    GameObject ringObj = new GameObject();
            //    ringObj.transform.position = Vector3.zero;
            //    Ring ring =  ringObj.AddComponent<Ring>();
            //    m_CandyRings.Add(ringObj);
            //    ring.m_Candies = new List<Candy>();
            //    ring.m_Radius = m_LevelBase.m_Rings[i].m_Radius;

            //    for (int j = 0;j< m_LevelBase.m_Rings[i].m_Balls.Length;j++)
            //    {
            //        GameObject obj = Instantiate(m_Candy);
            //        Candy candy = obj.GetComponent<Candy>();
            //        candy.transform.SetParent(ringObj.transform, false);
            //        candy.transform.localPosition = m_LevelBase.m_Rings[i].m_Balls[j].transform.localPosition;
            //        candy.SetColor(m_LevelBase.m_Rings[i].m_Balls[j].m_ColorNum);
            //        //candy.transform.localScale = m_LevelBase.m_Rings[i].m_Balls[j].transform.localScale;
            //        ring.m_Candies.Add(candy);
            //        m_Candies.Add(candy);
            //        m_ColorCount[m_LevelBase.m_Rings[i].m_Balls[j].m_ColorNum]++;
            //    }
            //}
        }

        public void SpawnCandy(float radius, int start = 0)
        {
            GameObject ring = new GameObject();
            ring.transform.position = Vector3.zero;
            ring.AddComponent<Ring>();
            ring.GetComponent<Ring>().m_Candies = new List<Candy>();

            float m_SpawnCount;
            float m_SpawnAngle;
            m_SpawnCount = (2 * Mathf.PI * radius) / 7;

            m_SpawnAngle = (360 / (float)Math.Floor(m_SpawnCount));

            for (int i = 0; i < Math.Floor(m_SpawnCount); i++)
            {
                Vector3 cordinates = Quaternion.Euler(0, 0, i * m_SpawnAngle) * new Vector3(radius, 0, 0);
                GameObject obj = Instantiate(m_CandyPrefab, cordinates, Quaternion.identity);
                m_Candies.Add(obj.GetComponent<Candy>());
                obj.GetComponent<Candy>().SetColor(UnityEngine.Random.Range(0, 6));

                //float delta = i * m_SpawnAngle+80*start;
                float delta = i * m_SpawnAngle;
                int num = (int)(delta / 20);
                num = num % 6;
                obj.GetComponent<Candy>().SetColor(num);
                m_ColorCount[num]++;
                obj.transform.SetParent(ring.transform, false);
                ring.GetComponent<Ring>().m_Candies.Add(obj.GetComponent<Candy>());
            }

            m_CandyRings.Add(ring);
            ring.GetComponent<Ring>().m_Radius = radius;
        }



        public void CheckNearCandies()
        {
            foreach (Candy candy1 in m_Candies)
            {
                foreach (Candy candy2 in m_Candies)
                {
                    //print("find");

                    if (candy1 == candy2 || candy1.m_ColorNum != candy2.m_ColorNum)
                        continue;

                    if (Vector3.Distance(candy1.transform.position, candy2.transform.position) <= 10)
                    {

                        if (!candy1.m_NearCandies.Contains(candy2))
                        {

                            candy1.m_NearCandies.Add(candy2);
                            candy2.m_NearCandies.Add(candy1);
                        }
                    }

                }
            }
        }

        public void StartUpdateRadius()
        {
            StartCoroutine(Co_UpdateRadius());
        }

        public void ReloadScene()
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }

        IEnumerator Co_UpdateRadius()
        {
            for (int i = 0; i < m_CandyRings.Count; i++)
            {
                float radius = m_CandyRings[i].GetComponent<Ring>().m_Radius;
                m_CandyRings[i].GetComponent<Ring>().UpdateRadius(radius - 2);
                yield return new WaitForSeconds(.2f);
            }

            //float[] startRadius = new float[m_CandyRings.Count];

            //for (int i = 0;i< m_CandyRings.Count;i++)
            //{
            //    startRadius[i] = m_CandyRings[i].GetComponent<Ring>().m_Radius;
            //}

            //float lerp = 0;
            //while (lerp < 1)
            //{
            //    for (int i = 0; i < m_CandyRings.Count;i++)
            //    {
            //        m_CandyRings[i].GetComponent<Ring>().UpdateRadius(startRadius[i]-5*lerp);
            //    }
            //    lerp +=  Time.deltaTime;
            //    yield return null;
            //}

            //for (int i = 0; i < m_CandyRings.Count; i++)
            //{
            //    m_CandyRings[i].GetComponent<Ring>().UpdateRadius(startRadius[i] - 5);
            //}
        }
        public void ColorCandies()
        {
            foreach (Candy item in m_Candies)
            {
                float delta = Vector3.SignedAngle(item.transform.position, Vector3.right, Vector3.forward);
                delta += 180;
                int num = (int)(delta / 90);
                item.SetColor(num);
            }
        }

        public void HandleBallEnd()
        {
            m_BallDestroyed = true;
        }

        public void ExplosionSound()
        {

        }

        public void LightningPower()
        {
            StartCoroutine(Co_LightningPower());
        }


        IEnumerator Co_LightningPower()
        {
            CameraControl.Current.StartShake(.5f, 10);

            GameObject obj1 = Instantiate(m_LightningParticle);
            obj1.transform.position = new Vector3(0, 0, -2);
            Destroy(obj1, 6);

            foreach (Candy candy in m_Candies)
            {
                if (!candy.gameObject.activeSelf)
                    continue;

                if (Math.Abs(candy.transform.localPosition.y) <= 20)
                {
                    candy.DestroyAlone();
                }
            }

            yield return new WaitForSeconds(.6f);

            CameraControl.Current.StartShake(.5f, 10);
            obj1 = Instantiate(m_LightningParticle);
            obj1.transform.position = new Vector3(0, 0, -2);
            obj1.transform.rotation = Quaternion.Euler(0, 0, 90);
            Destroy(obj1, 6);

            foreach (Candy candy in m_Candies)
            {
                if (!candy.gameObject.activeSelf)
                    continue;

                if (Math.Abs(candy.transform.localPosition.x) <= 20)
                {
                    candy.DestroyAlone();
                }
            }
        }


        IEnumerator Co_StartLevel()
        {
            //SpawnFromEditor();
            //CameraControl.Current.GetComponent<Camera>().orthographicSize = 50;


            GameObject levelObj = m_Contents.m_Levels[m_DataStorage.Level].m_LevelPrefab;
            EditorBallBase[] balls = levelObj.GetComponentsInChildren<EditorBallBase>();






            //CameraControl.Current.ZoomCamera(170, 2);



            for (int i = 0; i < balls.Length; i++)
            {
                if (balls[i].m_TypeNum == 0)
                {
                    GameObject obj = Instantiate(m_CandyPrefab);
                    Candy candy = obj.GetComponent<Candy>();
                    candy.transform.localPosition = balls[i].transform.localPosition;
                    candy.SetColor(balls[i].m_ColorNum);
                    m_Candies.Add(candy);
                    m_ColorCount[candy.m_ColorNum]++;
                }
                else if (balls[i].m_TypeNum == 1)
                {
                    GameObject obj = Instantiate(m_BombPrefab);
                    obj.transform.localPosition = balls[i].transform.localPosition;
                }
                else if (balls[i].m_TypeNum == 2)
                {
                    GameObject obj = Instantiate(m_RockPrefab);
                    obj.transform.localPosition = balls[i].transform.localPosition;
                }

                yield return null;
            }

            CheckNearCandies();


            //Vector3[] startPos = new Vector3[m_Candies.Count];
            //Vector3[] endPos = new Vector3[m_Candies.Count];

            //for (int i = 0;i<m_Candies.Count;i++)
            //{
            //    endPos[i] = m_Candies[i].transform.position;
            //    Vector3 dir = endPos[i].normalized;
            //    startPos[i] = dir * 200;
            //    m_Candies[i].transform.position = startPos[i];
            //}

            //float lerp = 0;
            //while(lerp<1)
            //{
            //    for (int i = 0; i < m_Candies.Count; i++)
            //    {
            //        m_Candies[i].transform.position = Quaternion.Euler(0,0,100f*(1-lerp)) * Vector3.Lerp(startPos[i], endPos[i], lerp);
            //        //yield return null;
            //    }

            //    lerp += Time.deltaTime;
            //    yield return null;
            //}

            //for (int i = 0; i < m_Candies.Count; i++)
            //{
            //    m_Candies[i].transform.position = endPos[i];
            //}



            SpawnPlayer();
        }

        IEnumerator Co_HandleWin()
        {
            for (int i = 0; i < 10; i++)
            {
                Vector3 pos = new Vector3(UnityEngine.Random.Range(-50, 50), UnityEngine.Random.Range(-50, 50), -3);
                GameObject obj1 = Instantiate(m_FireworkParticle);
                obj1.transform.position = pos;
                Destroy(obj1, 6);

                yield return new WaitForSeconds(.3f);
            }

            yield return new WaitForSeconds(1);

            m_DataStorage.Level++;


            if (m_DataStorage.Level > 14)
            {
                m_DataStorage.Level = 0;
            }

            if (m_DataStorage.LevelUnlocked < m_DataStorage.Level)
                m_DataStorage.LevelUnlocked = m_DataStorage.Level;


            //reward power
            int reward = m_DataStorage.m_LevelPowerReward[m_DataStorage.Level];
            if (reward > 0)
            {
                m_DataStorage.m_PowerCounts[reward - 1]++;
            }
            m_DataStorage.SaveData();
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }
}